package gui.util;

import javax.swing.*;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ActionMapUIResource;
import java.awt.event.*;
import java.awt.*;

/**
 * STARÁ TŘÍDA - NEPOUŽÍVAT!!!!!!!
 * 
 * Maintenance tip - There were some tricks to getting this code working: 1. You
 * have to overwite addMouseListener() to do nothing 2. You have to add a mouse
 * event on mousePressed by calling super.addMouseListener() 3. You have to
 * replace the UIActionMap for the keyboard event "pressed" with your own one.
 * 4. You have to remove the UIActionMap for the keyboard event "released". 5.
 * You have to grab focus when the next state is entered, otherwise clicking on
 * the component won't get the focus. 6. You have to make a TristateDecorator as
 * a button model that wraps the original button model and does state
 * management.
 */
public class ThreestateCheckBox_Old extends JCheckBox
{
	/** This is a type-safe enumerated type */
	public enum State
	{
		SELECTED, NOT_SELECTED, DONT_CARE
	}

	private final TristateDecorator model;

	public ThreestateCheckBox_Old(String text, Icon icon, State initial){
		super(text, icon);
		// Add a listener for when the mouse is pressed
		super.addMouseListener(new ThreestateMouseListener());
		// Reset the keyboard action map
		ActionMap map = new ActionMapUIResource();
		map.put("pressed", new ThreestateAction());
		map.put("released", null);
		SwingUtilities.replaceUIActionMap(this, map);
		// set the model to the adapted model
		model = new TristateDecorator(getModel());
		setModel(model);
		setState(initial);
	}

	public ThreestateCheckBox_Old(String text, State initial){
		this(text, null, initial);
	}

	public ThreestateCheckBox_Old(String text){
		this(text, State.DONT_CARE);
	}

	public ThreestateCheckBox_Old(){
		this(null);
	}

	/** No one may add mouse listeners, not even Swing! */
	public void addMouseListener(MouseListener l){
	}

	/**
	 * Set the new state to either SELECTED, NOT_SELECTED or DONT_CARE. If state
	 * == null, it is treated as DONT_CARE.
	 */
	public void setState(State state){
		model.setState(state);
	}

	/**
	 * Return the current state, which is determined by the selection status of
	 * the model.
	 */
	public State getState(){
		return model.getState();
	}

	public void setSelected(boolean b){
		if(b){
			setState(State.SELECTED);
		}
		else{
			setState(State.NOT_SELECTED);
		}
	}
	
	protected void paintComponent(Graphics g) 
	{
		super.paintComponent(g);
		if(getState() == State.DONT_CARE)
		{
			g.setColor(new Color(127, 127, 127, 127));
			g.fillRect(6, 8, 9, 9);
		}
	}
	
	private void next(){
		grabFocus();
		model.nextState();
	}
	
	private class ThreestateMouseListener extends MouseAdapter
	{
		@Override public void mouseClicked(MouseEvent e){
			next();
		}
	}
	
	private class ThreestateAction extends AbstractAction
	{
		public void actionPerformed(ActionEvent e){
			next();
		}
	}

	/**
	 * Exactly which Design Pattern is this? Is it an Adapter, a Proxy or a
	 * Decorator? In this case, my vote lies with the Decorator, because we are
	 * extending functionality and "decorating" the original model with a more
	 * powerful model.
	 */
	private class TristateDecorator implements ButtonModel
	{
		private final ButtonModel other;
		private State state;

		private TristateDecorator(ButtonModel other){
			this.other = other;
		}

		private void setState(State state){
			this.state = state; 
			if(state == State.NOT_SELECTED){
				//other.setArmed(false);
				setPressed(false);
				setSelected(false);
			}
			else if(state == State.SELECTED){
				//other.setArmed(false);
				setPressed(false);
				setSelected(true);
			}
			else{ // either "null" or DONT_CARE
				//other.setArmed(true);
				setPressed(true);
				setSelected(false);
			}
		}

		/**
		 * The current state is embedded in the selection / armed state of the
		 * model. We return the SELECTED state when the checkbox is selected but
		 * not armed, DONT_CARE state when the checkbox is selected and armed
		 * (grey) and NOT_SELECTED when the checkbox is deselected.
		 */
		private State getState(){
			return state;
			/*if(isSelected()){
				// normal black tick
				return SELECTED;
			}
			else if(isArmed()){
				// don't care grey tick
				return DONT_CARE;
			}
			else{
				// normal deselected
				return NOT_SELECTED;
			}*/
		}

		/** We rotate between NOT_SELECTED, SELECTED and DONT_CARE. */
		private void nextState(){
			System.out.println("Next state");
			if(state == State.NOT_SELECTED){
				setState(State.SELECTED);
			}
			else if(state == State.SELECTED){
				setState(State.DONT_CARE);
			}
			else if(state == State.DONT_CARE){
				setState(State.NOT_SELECTED);
			}
		}

		/** Filter: No one may change the armed status except us. */
		public void setArmed(boolean b){
			other.setArmed(b);
		}

		/**
		 * We disable focusing on the component when it is not enabled.
		 */
		public void setEnabled(boolean b){
			setFocusable(b);
			other.setEnabled(b);
		}

		/**
		 * All these methods simply delegate to the "other" model that is being
		 * decorated.
		 */
		public boolean isArmed(){
			return other.isArmed();
		}

		public boolean isSelected(){
			return other.isSelected();
		}

		public boolean isEnabled(){
			return other.isEnabled();
		}

		public boolean isPressed(){
			return other.isPressed();
		}

		public boolean isRollover(){
			return other.isRollover();
		}

		public void setSelected(boolean b){
			other.setSelected(b);
		}

		public void setPressed(boolean b){
			other.setPressed(b);
		}

		public void setRollover(boolean b){
			other.setRollover(b);
		}

		public void setMnemonic(int key){
			other.setMnemonic(key);
		}

		public int getMnemonic(){
			return other.getMnemonic();
		}

		public void setActionCommand(String s){
			other.setActionCommand(s);
		}

		public String getActionCommand(){
			return other.getActionCommand();
		}

		public void setGroup(ButtonGroup group){
			other.setGroup(group);
		}

		public void addActionListener(ActionListener l){
			other.addActionListener(l);
		}

		public void removeActionListener(ActionListener l){
			other.removeActionListener(l);
		}

		public void addItemListener(ItemListener l){
			other.addItemListener(l);
		}

		public void removeItemListener(ItemListener l){
			other.removeItemListener(l);
		}

		public void addChangeListener(ChangeListener l){
			other.addChangeListener(l);
		}

		public void removeChangeListener(ChangeListener l){
			other.removeChangeListener(l);
		}

		public Object[] getSelectedObjects(){
			return other.getSelectedObjects();
		}
	}

	public static class TristateCheckBoxTest
	{
		public static void main(String args[]) throws Exception{
			JFrame frame = new JFrame("TristateCheckBoxTest");
			frame.getContentPane().setLayout(new GridLayout(0, 1, 5, 5));
			final ThreestateCheckBox_Old swingBox =
						new ThreestateCheckBox_Old("Testing the tristate checkbox");
			swingBox.setMnemonic('T');
			frame.getContentPane().add(swingBox);
			frame.getContentPane().add(new JCheckBox("The normal checkbox"));
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			final ThreestateCheckBox_Old winBox =
						new ThreestateCheckBox_Old("Testing the tristate checkbox",
									State.SELECTED);
			frame.getContentPane().add(winBox);
			final JCheckBox winNormal = new JCheckBox("The normal checkbox");
			frame.getContentPane().add(winNormal);

			frame.getContentPane().add(new JButton("ABC"));
			// wait for 3 seconds, then enable all check boxes
			new Thread()
			{
				{
					start();
				}

				public void run(){
						winBox.setEnabled(false);
						winNormal.setEnabled(false);
						winBox.setEnabled(true);
						winNormal.setEnabled(true);
				}
			};
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			frame.pack();
			frame.show();
		}
	}
}
